package com.hd123.rumba.util;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

public class Signer {

  /**
   * @param args
   */
  public static void main(String[] args) throws Exception {
    File privateKeyFile = new File("c:/temp/private");
    File publicKeyFile = new File("c:/temp/public");
    
    // 生成密钥对并存入私钥文件和公钥文件
    Signer a = new Signer();
    a.generateKeys();
    a.savePrivateKey(privateKeyFile);
    a.savePublicKey(publicKeyFile);
    
    // 取得数据签名
    Signer s = new Signer();
    s.loadPrivateKey(privateKeyFile);
    byte[] data = "这是明文".getBytes();
    byte[] sign = s.sign(data);
   
    BASE64Encoder b64e = new BASE64Encoder();
    String signString = b64e.encode(sign);
    System.out.println("signature: \n" + signString);
    
    // 验证数据签名
    Signer v = new Signer();
    v.loadPublicKey(publicKeyFile);
    BASE64Decoder b64d = new BASE64Decoder();
    sign = b64d.decodeBuffer(signString);
    System.out.println(v.verify(data, sign));
  }

  PrivateKey privateKey;
  PublicKey publicKey;

  public void generateKeys() throws Exception {
    KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA");
    SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
    random.setSeed("charlie".getBytes());
    keyGen.initialize(1024, random);
    KeyPair pair = keyGen.generateKeyPair();
    privateKey = pair.getPrivate();
    publicKey = pair.getPublic();
  }

  public void savePrivateKey(File file) throws Exception {
    writeFile(file, privateKey.getEncoded());
  }
  
  public void savePublicKey(File file) throws Exception {
    writeFile(file, publicKey.getEncoded());
  }

  private void writeFile(File file, byte[] data) throws Exception {
    FileOutputStream out = new FileOutputStream(file);
    out.write(data);
    out.flush();
    out.close();
  }
  
  public void loadPrivateKey(File file) throws Exception {
    loadPrivateKey(new FileInputStream(file));
  }
  
  public void loadPrivateKey(InputStream is) throws Exception {
    byte[] encodedKey = readStream(is);
    PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(encodedKey);
    KeyFactory keyFactory = KeyFactory.getInstance("DSA");
    privateKey = keyFactory.generatePrivate(keySpec);
  }

  public void loadPublicKey(File file) throws Exception {
    loadPublicKey(new FileInputStream(file));
  }
  
  public void loadPublicKey(InputStream is) throws Exception {
    byte[] encodedKey = readStream(is);
    X509EncodedKeySpec keySpec = new X509EncodedKeySpec(encodedKey);
    KeyFactory keyFactory = KeyFactory.getInstance("DSA");
    publicKey = keyFactory.generatePublic(keySpec);
  }
  
  public byte[] readStream(InputStream in) throws Exception {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    byte[] b = new byte[128];
    int bytesRead = -1;
    while (-1 != (bytesRead = in.read(b, 0, b.length))) {
      out.write(b, 0, bytesRead);
    }
    out.flush();
    byte[] result = out.toByteArray().clone();
    in.close();
    out.close();
    return result;
  }

  public byte[] sign(byte[] data) throws Exception {
    Signature dsa = Signature.getInstance("SHA1withDSA");
    dsa.initSign(privateKey);
    dsa.update(data);
    return dsa.sign();
  }

  public boolean verify(byte[] data, byte[] sig) throws Exception {
    Signature dsa = Signature.getInstance("SHA1withDSA");
    dsa.initVerify(publicKey);
    dsa.update(data);
    return dsa.verify(sig);
  }
}
